package com.mars.common.util;

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Pattern;

/**
 * @author wyt
 */
@Slf4j
public class BeanPropertyUtil {

    private static final Pattern GET_PATTERN = Pattern.compile("^get[A-Z].*");
    private static final Pattern IS_PATTERN = Pattern.compile("^is[A-Z].*");
    private static final Map<Class<?>, Supplier<Object>> TYPE_ENUM = Maps.newHashMap();

    static {
        TYPE_ENUM.put(String.class, () -> "");
        TYPE_ENUM.put(Byte.class, () -> 0);
        TYPE_ENUM.put(Short.class, () -> 0);
        TYPE_ENUM.put(Integer.class, () -> 0);
        TYPE_ENUM.put(Long.class, () -> 0L);
        TYPE_ENUM.put(Float.class, () -> 0.0f);
        TYPE_ENUM.put(Double.class, () -> 0.0);
        TYPE_ENUM.put(Boolean.class, () -> false);
        TYPE_ENUM.put(Date.class, Date::new);
    }

    private static String fnToFieldName(SFunction fn) {
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
            String getter = serializedLambda.getImplMethodName();
            if (GET_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(3);
            } else if (IS_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(2);
            }
            return Introspector.decapitalize(getter);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取类的相关字段
     *
     * @param fn
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> String getBeanFieldName(SFunction<T, R> fn) {
        return fnToFieldName(fn);
    }


    /**
     * 将对象中为null的字段改为''
     *
     * @param vo
     * @return
     */
    public static <T> T replaceIfNull(T vo) {
        Field[] fields = vo.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Type type = field.getGenericType();
            if (TYPE_ENUM.containsKey(type)) {
                try {
                    Object value = field.get(vo);
                    if (ObjectUtils.isEmpty(value)) {
                        field.set(vo, TYPE_ENUM.get(type).get());
                    }
                } catch (Exception e) {
                    log.error("error msg:{}", e.getMessage());
                }
            }
        }
        return vo;
    }

    /**
     * 批量操作
     *
     * @param collection
     * @param <T>
     * @return
     */
    public static <T> Collection<T> replaceIfNull(Collection<T> collection) {
        for (Object t : collection) {
            replaceIfNull(t);
        }
        return collection;
    }

}
